#ifndef __MY_DATA__
#define __MY_DATA__
#include <unordered_map>
#include <pthread.h>
#include <vector>
#include "Util.hpp"
#include "Config.hpp"
#include <sw/redis++/redis++.h>
static const string DefaultUrl = "tcp://redis:6379";
namespace Cloud
{
    struct BackupInfo // 备份信息类
    {
    public:
        BackupInfo() {}
        BackupInfo(const string &filepath)
        {
            Cloud::FileUtil fu(filepath);
            Cloud::Config *config = Cloud::Config::GetInstance();
            if (fu.Exists() == false)
            {
                ERROR("%s", " Backup file not exists ");
                exit(-1);
            }
            pack_flag = false;
            packRunning = false;
            fsize = fu.FileSize();
            atime = fu.LastATime();
            mtime = fu.LastMTime();
            realpath = filepath;
            packpath = config->GetPackDir() + fu.GetFileName() + config->GetPackFileSuffix();
            url = config->GetDownLoadprefix() + fu.GetFileName();
        }
        BackupInfo &operator()(const string &filepath)
        {
            Cloud::FileUtil fu(filepath);
            Cloud::Config *config = Cloud::Config::GetInstance();
            if (fu.Exists() == false)
            {
                ERROR("%s", "BackupInfo: file not exists");
                exit(-1);
            }
            pack_flag = false;
            packRunning = false;
            fsize = fu.FileSize();
            atime = fu.LastATime();
            mtime = fu.LastMTime();
            realpath = filepath;
            packpath = config->GetPackDir() + fu.GetFileName() + config->GetPackFileSuffix();
            url = config->GetDownLoadprefix() + fu.GetFileName();
            return *this;
        }

    public:
        bool pack_flag;   // 文件压缩标志
        bool packRunning; // 文件正在压缩中标志
        size_t fsize;     // 文件大小
        time_t atime;     // 最后一次访问时间
        time_t mtime;     // 最后一次修改时间
        string realpath;  // 文件实际存储路径
        string packpath;  // 压缩包存放路径
        string url;       // 下载文件url路径
    };

    class DataManger // 数据管理类
    {
    private:
        sw::redis::Redis _redis; // 定义一个redis对象
    public:
        DataManger(const string &url = DefaultUrl) : _redis(url)
        {
            string ret = _redis.ping();
            if(ret=="PONG")
                INFO("Redis Init Complate,Establish a link");
        }
        ~DataManger()
        {
        }

        bool Insert(const BackupInfo &info) // 新增数据
        {
            Json::Value root;
            root["pack_flag"] = (Json::UInt64)info.pack_flag;
            root["packRunning"] = (Json::Int64)info.packRunning;
            root["fsize"] = (Json::Int64)info.fsize;
            root["atime"] = (Json::Int64)info.atime;
            root["mtime"] = (Json::Int64)info.mtime;
            root["realpath"] = info.realpath.c_str();
            root["packpath"] = info.packpath.c_str();
            root["url"] = info.url.c_str();
            string body;
            JsonUtil::Serialize(root, &body);

            bool ret = _redis.set(info.url, body);
            if (ret)
            {
                INFO("%s%s", "Redis Inserted a piece of metadata,Key = ", info.url.c_str());
                return true;
            }
            ERROR("%s%s", "Redis Insert MetaData Fail,Key = ", info.url.c_str());
            return false;
        }
        bool Update(const BackupInfo &info) // 更新数据
        {
            Insert(info);
            return true;
        }
        bool GetOneByUrl(const string &url, BackupInfo *info) // URL方式获取下载单个文件信息
        {
            auto ret = _redis.get(url);
            if (ret) // optional 可以隐式转化为bool类型
            {
                Json::Value root;
                JsonUtil::UnSerialize(ret.value(), &root);

                for (int i = 0; i < root.size(); i++)
                {
                    info->pack_flag = root["pack_flag"].asBool();
                    info->packRunning = root["packRunning"].asBool();
                    info->atime = root["atime"].asInt64();
                    info->mtime = root["mtime"].asInt64();
                    info->fsize = root["fsize"].asInt64();
                    info->realpath = root["realpath"].asString();
                    info->packpath = root["packpath"].asString();
                    info->url = root["url"].asString();
                }
                return true;
            }
            ERROR("%s%s%s", "The key = ", url.c_str(), "does not exist in Redis");
            return false;
        }
        bool GetOneByRealpath(const string &realpath, BackupInfo *info) // 真实路径获取一个备份信息
        {
            string url;
            size_t pos = realpath.find_last_of("/");
            if (pos == string::npos)
            {
                url = realpath;
            }
            url = Config::GetInstance()->GetDownLoadprefix() + realpath.substr(pos + 1);
            auto value = _redis.exists(url); // 返回key的个数
            if (value > 0)
            {
                auto ret = _redis.get(url);

                Json::Value root;
                JsonUtil::UnSerialize(ret.value(), &root);

                info->pack_flag = root["pack_flag"].asBool();
                info->packRunning = root["packRunning"].asBool();
                info->atime = root["atime"].asInt64();
                info->mtime = root["mtime"].asInt64();
                info->fsize = root["fsize"].asInt64();
                info->realpath = root["realpath"].asString();
                info->packpath = root["packpath"].asString();
                info->url = root["url"].asString();

                return true;
            }
            ERROR("%s%s%s", "The key = ", url.c_str(), "does not exist in Redis");
            return false;
        }
        void GetAll(vector<BackupInfo> *array) // 获取所有文件的备份信息
        {
            vector<string> containter;
            auto it = back_inserter(containter);
            size_t cursor = _redis.scan(0, it);
            while (cursor != 0)
            {
                cursor = _redis.scan(cursor, it);
            }

            if (containter.empty())
            {
                return; // 如果没有键，直接返回
            }
            vector<string> Datas;
            auto values = back_inserter(Datas);
            _redis.mget(containter.begin(), containter.end(), values);
            for (auto &body : Datas)
            {
                Json::Value root;
                JsonUtil::UnSerialize(body, &root);
                BackupInfo info;

                info.pack_flag = root["pack_flag"].asBool();
                info.packRunning = root["packRunning"].asBool();
                info.atime = root["atime"].asInt64();
                info.mtime = root["mtime"].asInt64();
                info.fsize = root["fsize"].asInt64();
                info.realpath = root["realpath"].asString();
                info.packpath = root["packpath"].asString();
                info.url = root["url"].asString();

                array->push_back(info);
            }
        }
    };
}

//     class DataManger // 数据管理类  ----->文件持久化备份信息
//     {
//     private:
//         string backup_file;                            // 持久化存储文件
//         std::unordered_map<string, BackupInfo> _table; // 内存中建立url与备份信息映射表
//         pthread_rwlock_t rwlock;                       // 定义一个读写锁
//     public:
//         DataManger()
//         {
//             backup_file = Cloud::Config::GetInstance()->GetBackUpFile();
//             pthread_rwlock_init(&rwlock, nullptr);
//             InitLoad();
//         }
//         ~DataManger()
//         {
//             pthread_rwlock_destroy(&rwlock);
//         }

//         bool InitLoad() // 初始化加载，将数据加载到内存中
//         {
//             DEBUG("%s", "Hot data loading......");
//             string body;
//             FileUtil fu(backup_file);
//             if (fu.Exists() == false)
//                 return true;
//             fu.GetCentent(&body);
//             Json::Value root;
//             JsonUtil::UnSerialize(body, &root);

//             for (int i = 0; i < root.size(); i++)
//             {
//                 BackupInfo info;
//                 info.pack_flag = root[i]["pack_flag"].asBool();
//                 info.packRunning = root[i]["packRunning"].asBool();
//                 info.atime = root[i]["atime"].asInt64();
//                 info.mtime = root[i]["mtime"].asInt64();
//                 info.fsize = root[i]["fsize"].asInt64();
//                 info.realpath = root[i]["realpath"].asString();
//                 info.packpath = root[i]["packpath"].asString();
//                 info.url = root[i]["url"].asString();
//                 Insert(info);
//             }
//             return true;
//         }

//         bool Storage() // 每次修改文件或新增文件都要进行持久化存储
//         {
//             // 1、读取数据
//             vector<BackupInfo> array;
//             GetAll(&array);
//             // 2、对数据进行序列化
//             Json::Value root;
//             for (auto &e : array)
//             {
//                 Json::Value item;
//                 item["pack_flag"] = (Json::Int64)e.pack_flag;
//                 item["packRunning"] = (Json::Int64)e.packRunning;
//                 item["fsize"] = (Json::Int64)e.fsize;
//                 item["atime"] = (Json::Int64)e.atime;
//                 item["mtime"] = (Json::Int64)e.mtime;
//                 item["realpath"] = e.realpath;
//                 item["packpath"] = e.packpath;
//                 item["url"] = e.url;
//                 root.append(item);
//             }
//             string body;
//             JsonUtil::Serialize(root, &body);
//             // 3、将数据写入文件    ---------------------->此处后续可以用redis进行保存
//             FileUtil fu(backup_file);
//             fu.SetCentent(body);
//             return true;
//         }
//         bool Insert(const BackupInfo &info) // 新增文件
//         {
//             pthread_rwlock_wrlock(&rwlock);
//             _table[info.url] = info;
//             pthread_rwlock_unlock(&rwlock);
//             Storage();
//             return true;
//         }
//         bool Update(const BackupInfo &info) // 修改文件
//         {
//             pthread_rwlock_wrlock(&rwlock);
//             _table[info.url] = info;
//             pthread_rwlock_unlock(&rwlock);
//             Storage();
//             return true;
//         }
//         bool GetOneByUrl(const string &url, BackupInfo *info) // URL方式获取下载单个文件信息
//         {
//             // pthread_rwlock_wrlock(&rwlock);
//             pthread_rwlock_rdlock(&rwlock);
//             if (_table.find(url) == _table.end())
//             {
//                 pthread_rwlock_unlock(&rwlock);
//                 return false;
//             }
//             *info = _table[url];
//             pthread_rwlock_unlock(&rwlock);
//             return true;
//         }
//         bool GetOneByRealpath(const string &realpath, BackupInfo *info) // 真实路径获取一个备份信息
//         {
//             // pthread_rwlock_wrlock(&rwlock);
//             pthread_rwlock_rdlock(&rwlock);
//             for (auto &e : _table)
//             {
//                 if (e.second.realpath == realpath)
//                 {
//                     *info = e.second;
//                     pthread_rwlock_unlock(&rwlock);
//                     return true;
//                 }
//             }
//             pthread_rwlock_unlock(&rwlock);
//             return false;
//         }
//         bool GetAll(vector<BackupInfo> *array) // 获取所有文件的备份信息
//         {
//             // pthread_rwlock_wrlock(&rwlock);---------------->此处目前觉的应该使用读者锁而不是写着锁
//             pthread_rwlock_rdlock(&rwlock);
//             for (auto &e : _table)
//             {
//                 array->push_back(e.second);
//             }
//             pthread_rwlock_unlock(&rwlock);
//             // pthread_rwlock_unlock(&rwlock);
//             return true;
//         }
//     };
// }

#endif